/* Janus Chat - Version 1.0
 * Authors: Matthew Perry
 *          Michael Freid
 *          Marc Latou
 *          Richard Lee
 *
 * The Janus Chat Client is a highly secured
 * peer-to-peer chat client designed to facilitate
 * the transfer of sensitive data or as a communication
 * medium for the extra paranoid
 *
 * This file contains the implementation for the ChatTab
 * QT class which is where the user will be spending most */

#include "chattab.h"
#include "smilies.h"
#include "../lib/exceptions.h"
#include "ui_chattab.h"
#include <QMessageBox>
#include <QEvent>
#include <QKeyEvent>

/* The ChatTab constructor:
 * This constructor takes in a socket
 * and creates a chat object which can manage it
 * It also connects the Chat objects's signals with
 * some slots for displaying information. This function will
 * also read any data that may be sitting in the socket */
ChatTab::ChatTab(User* user, QTcpSocket* sock, bool host, QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ChatTab),
    myChat( user, host, sock )
{
    //Initialize this class' UI Elements (Widgets)
    ui->setupUi(this);

    //Initialize this class' user
    myUser = user;

    //Establish signal and slot relationships
    connect( &myChat, SIGNAL(newMsg(Message,QString)), this, SLOT(printMsg(Message,QString)) );
    connect( &myChat, SIGNAL(disMsg(QString)), this, SLOT(printDis(QString)) );

    //Filter enter key for sending
    ui->textInput->installEventFilter( this );

    //Empty the chat socket
    myChat.readSome();
    //Start key exchange if the user created this chat
    if( host )
        myChat.startKeyExchange();
}

/* Destructor */
ChatTab::~ChatTab()
{
    delete ui;
}

/* The disconnectChat function:
 * This function simply calls the chat's
 * disengage function which cleans up the chat
 * and disconnects the socket */
void ChatTab::disconnectChat()
{
    myChat.disengage();
}

/* The printMsg slot:
 * This slot is activated by a signal from the
 * chat object that a new message has been recieved
 * This slot displays that message with a given color */
void ChatTab::printMsg( const Message& msg, const QString& color )
{
    //Create string to append format: "NAME: MSG"
    QString output = "<b><font color=" + color + ">" +
                     QString::fromStdString( msg[0] ) +
                     "</font></b>: " +
                     QString::fromStdString( msg[1] );
    //The textOutput uses HTML, not plaintext for display
    output.replace( '\n', "<br>" );
    //Append string to the output box
    ui->textOutput->append( output );
}

/* The printDis slot:
 * This slot simply prints a disconnect message
 * It is activated by a signal from the chat that
 * someone has disconnected */
void ChatTab::printDis( const QString& name )
{
    //Create a disconnect message
    QString output = "<i><font color=grey >" + name +
                     " has disconnected from this chat</font></i>";
    //Append string to the output box
    ui->textOutput->append( output );
}

/* The Send Button slot:
 * This slot is activated when the
 * send button is clicked or when the
 * enter key is pressed. It tells the chat
 * object to write a new message */
void ChatTab::on_buttonSend_clicked()
{
    //Message creation can cause exceptions, catch them
    try
    {
        //If the message is too long, create multiple messages
        int msgLen = ui->textInput->toPlainText().size();
        int allowedLen =  Message::BODY_SIZE - (myUser->getMoniker().size() + 8);
        string body = ui->textInput->toPlainText().toStdString();
        int i = 0;

        do
        {
            //Convert the text you've written into a message
            Message msg( Message::DecryptStandard );
            msg.addField( myUser->getMoniker() );
            msg.addField( body.substr( i * allowedLen, allowedLen ) );

            //Prepare next iteration
            msgLen -= allowedLen;
            i++;

            //Write the message to the chat
            myChat.writeMsg( msg );
        } while( msgLen > 0 );

        //Clear the input box
        ui->textInput->clear();
    }
    catch( BaseException* e )
    {
        //Pop up message box with the errors
        QMessageBox msgBox;
        msgBox.setWindowTitle( "Critical Socket Error" );
        msgBox.setText( "An error has occured while creating a message" );
        msgBox.setInformativeText( QString::fromStdString( e->what() ) );
        msgBox.setIcon( QMessageBox::Critical );
        msgBox.exec();
    }
}

/* The smiley button slot:
 * Activated when the smiley button is clicked,
 * This slot pops up a window to select a smiley
 * and inserts it into the input window */
void ChatTab::on_buttonSmiley_clicked()
{
    //Make new smiley dialog
    Smilies s( this );
    //Connect smiley signal
    connect( &s, SIGNAL(smiley(QString)), ui->textInput, SLOT(insertPlainText(QString)) );
    //Spawn smiley dialog
    s.exec();
}

/* The eventFilter:
 * For ease of use, pressing the Enter key should
 * automatically send a message. This function catches
 * enter key presses and redirects them to the send button */
bool ChatTab::eventFilter( QObject* obj, QEvent* event )
{
    //The event has to be a keypress event
    if( event->type() == QEvent::KeyPress )
    {
        //Cast the generic event to a keyevent
        QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
        //Check that the key is the enter key
        if( keyEvent->key() == Qt::Key_Return )
        {
            //Press the send button for the user
            this->on_buttonSend_clicked();
            return true;
        }
    }
    //If it is not one of the above, behave normally
    return QObject::eventFilter( obj, event );
}
